<template>
  <div class="cc-edit-table cc-flex-column cc-grow-height" v-if="!initializing">
    <div v-if="!disabled && showOperateButton" style="margin-bottom: 5px">
      <span>
        <span>
          <span style="font-weight:600;margin-right: 10px">{{compName}}</span>
          <span> 新增&nbsp;</span>
        </span>
        <el-input
          v-model.number="newRow"
          auto-complete="off"
          style="width:50px"
        ></el-input>
        <span>&nbsp;行&nbsp;</span>
      </span>
      <el-button type="success" @click="addNew">确定</el-button>
    </div>
    <el-form
      :model="formData"
      :disabled="disabled"
      ref="dataForm"
      label-width="0px"
      label-position="right"
      class="cc-flex-column cc-grow-height"
    >
      <!--表格栏-->
      <el-table
        ref="dataTable"
        :class="['cc-table', 'cc-grow-height', disabled ? '': 'edit-table']"
        width="100%"
        border
        :data="formData.list"
        :row-key="getRowKey"
        :show-overflow-tooltip="disabled"
      >
        <el-table-column
          v-for="(column, index) in columnList"
          :key="index"
          header-align="center"
          align="left"
          :prop="column.fieldName"
          :label="column.label"
          :width="column.width < 0 ? null : column.width"
          :min-width="column.width < 0 ? column.width * -1 : null"
          :show-overflow-tooltip="(disabled || column.readonly) && column.fieldType !== '视频' ?
          {
            'effect': 'light',
            'raw-content': false,
            'placement': 'bottom',
            'popper-class': 'padding-10-15'
          } : false"
        >
          <template #header>
            <span>{{column.aliasName}}</span>
            <el-tooltip v-if="column.description" effect="light" popper-class="padding-10-15">
              <cc-icon iconId="018dca8ec9890493be26" style="margin-left: 5px"/>
              <template #content>
                <div>{{column.description}}</div>
              </template>
            </el-tooltip>
          </template>
          <template v-slot="{ $index }">
            <el-form-item
              :prop="rules[column.fieldName] ? 'list.' + $index +'.' + column.fieldName : null"
              :rules="rules[column.fieldName]"
            >
              <table-edit-item
                :index="$index"
                :column="column"
                @change="changeValue"
              />
            </el-form-item>
          </template>
        </el-table-column>
        <el-table-column
          v-if="!disabled && showOperateButton"
          label="操作"
          width="60"
          header-align="center"
          align="center"
        >
          <template v-slot="{ row }">
            <el-button
              @click="handleDeleteRow(row)"
              type="danger"
              link
            >删除</el-button>
          </template>
        </el-table-column>
      </el-table>
    </el-form>
  </div>
</template>

<script setup>
import { ref, provide, onMounted, watch, nextTick, inject } from 'vue';
import loading from "@/utils/loading";
import api from "@/http/api";
import tool from "@/utils/tool";
import TableEditItem from "@/codeless/view/table-edit-item.vue";
import { useUserStore } from "@/pinia/modules/user";
import { getDataTable } from '@/utils/codeless';
import { ElMessage, ElMessageBox } from "element-plus";

const props = defineProps({
  dataTableId: String,
  autofillList: {
    type: Array,
    default: () => []
  },
  fieldList: {
    type: Array,
    default: () => []
  },
  formFieldList: {
    type: Array,
    default: () => []
  },
  dataList: {
    type: Array,
    default: () => []
  },
  defaultValue: {
    type: Object,
    default: () => {}
  },
  disabled: {
    type: Boolean,
    default: false
  },
  showOperateButton: {
    type: Boolean,
    default: true
  },
  required: String,
  compName: String,
  customFun: Object,
});

const initializing = ref(true);
const disabled = ref(false);
const columnList = ref([]);
const dataTable = ref();
const dataForm = ref();
const rules = ref({});
const formData = ref({ list: [] });
const defaultData = ref({});
const newRow = ref(1);
const newRowFlag = ref(0);
const userStore = useUserStore();
const page = inject('page', { getPageData: () => {} });
provide('formData', formData);

const addNew = () => {
  for (let i=0;i<newRow.value;i++) {
    const data = Object.assign(
      {},
      defaultData.value,
      props.defaultValue,
      {newRowFlag: ++newRowFlag.value});
    formData.value.list.push(data);
  }
};

const handleDeleteRow = (row) => {
  ElMessageBox.confirm("请确认是否删除？", "提示", { type: "info" }).then(() => {
    for (let i=0;i<formData.value.list.length;i++) {
      if (row.newRowFlag !== undefined && row.newRowFlag === formData.value.list[i].newRowFlag) {
        formData.value.list.splice(i, 1);
        return;
      }
    }
  }).catch(() => {});
};

const getRowKey = (row) => {
  return row.newRowFlag;
};

const initByTableId = async(tableId) => {
  loading.showLoading();
  try {
    const fieldList = await loadTableFieldList(tableId);
    await initColumnList(fieldList.filter(field => field.fieldName !== 'update_time' && field.fieldName !== 'create_time'));
    await initTableData();
    await initFormRules();
    await initDefaultData(fieldList);
    loading.hideLoading();
  } finally {
    loading.hideLoading();
  }
};

const initByFormField = async(fieldList) => {
  loading.showLoading();
  try {
    await initColumnList(fieldList);
    await initTableData();
    await initFormRules();
    await initDefaultData(fieldList);
    loading.hideLoading();
  } finally {
    loading.hideLoading();
  }
};

const loadTableFieldList = async(tableId) => {
  const table = await getDataTable(tableId);
  return table.fieldList;
};

const initTableData = async() => {
  formData.value.list = [];
  (props.dataList || []).forEach(data => {
    data.newRowFlag = ++newRowFlag.value
    formData.value.list.push(Object.assign({}, data))
  });
};

const initColumnList = async(list) => {
  let fieldList = tool.deepClone(list) || [];
  fieldList.forEach(item => {
    let find = props.fieldList.find(field => field.id === item.fieldId);
    if (find) {
      item.label = item.aliasName || item.fieldName;
      item.aliasName = item.aliasName || find.aliasName || find.showName;
      item.width = item.colCnt && Math.abs(item.colCnt) < 24 ? item.colCnt * 10 : item.colCnt;
      item.fieldType = find.fieldType;
      item.fieldSize = find.fieldSize;
      item.inputType = find.inputType;
      item.enumerate = find.enumerate;
      item.enumerateType = find.enumerateType;
      item.relevanceType = find.relevanceType;
      item.relevanceDict = find.relevanceDict;
      item.enumerateValue = find.enumerateValue;
      item.dataField = find;
      item.description = item.description || find.description || '';
    }
  });

  columnList.value = fieldList.filter(item => item.hide !== '1');
};

const initFormRules = async() => {
  rules.value = {};
  columnList.value.forEach(column => {
    let field = column.dataField;

    let ruleList = [];
    if (field.required === '1' || column.required === '1') {
      ruleList.push({
        required: true,
        message: "【" + column.label + "】为必填项",
        trigger: ['blur', 'change']
      });
    }
    switch (field.fieldType) {
      case '字符':
        ruleList.push({
          max: field.fieldSize || 1000,
          message: "【" + column.label + "】" +
            "长度必须小于等于 " + (field.fieldSize || 1000) + " 个字符",
          trigger: ['blur', 'change']
        });
        break;
      case '整数':
      case '小数':
        ruleList.push({
          min: field.minValue || 0,
          max: field.maxValue || 2147483647,
          minEqu: field.containMinValue === '1',
          maxEqu: field.containMaxValue === '1',
          message: "【" + column.label + "】" +
            "必须大于" + (field.containMinValue === '1' ? '等于' : '') + ' ' +
            (field.minValue || 0) +
            " 小于" + (field.containMaxValue === '1' ? '等于' : '') + ' ' +
            (field.maxValue || 2147483647),
          trigger: ['blur', 'change'],
          validator: (rule, value, callback) => {
            if (value !== 0 && !value) {
              callback();
              return;
            }

            if (rule.minEqu && value < rule.min) {
              callback(new Error(rule.message));
            } else if (!rule.minEqu && value <= rule.min) {
              callback(new Error(rule.message));
            } else if (rule.maxEqu && value > rule.max) {
              callback(new Error(rule.message));
            } else if (!rule.maxEqu && value >= rule.max) {
              callback(new Error(rule.message));
            }

            callback();
          }
        });
        break;
    }
    if (ruleList.length > 0) {
      rules.value[field.fieldName] = ruleList;
    }
  });
};

const initDefaultData = async(fieldList) => {
  defaultData.value = {};
  let pkName = getPKName(props.fieldList);
  if (pkName && !(props.initData && props.initData[pkName]) && !disabled.value) {
    for (let field of fieldList) {
      defaultData.value[field.fieldName] = null;
      let res = await userStore.parseSymbol(field.defaultValue);
      if (res) {
        defaultData.value[field.fieldName] = res;
      }
    }
  }
};

const getPKName = (list) => {
  if (!list) return null;
  for (let field of list) {
    if (field.primaryKey === '1') {
      return field.fieldName;
    }
  }
  return null;
};

const validate = (callback) => {
  const promise =  new Promise((resolve, reject) => {
    dataForm.value.validate(valid => resolve(valid)).catch(e => reject(e));
  });
  promise.then(valid => {
    if (props.required === '1' && (!formData.value.list || formData.value.list.length === 0)) {
      ElMessage.error('板块【' + props.compName + '】' + "必须录入至少1条数据！");
    } else {
      callback(valid);
    }
  }).catch(() => callback(false));
  return promise;
};

const changeValue = (field, data) => {
  autofillValue(data, field.fieldName);
};

const getData = () => {
  return formData.value.list;
};

const init = async() => {
  if (!props.dataTableId && props.formFieldList.length <= 0) {
    return;
  }

  initializing.value = true;
  disabled.value = (props.operate === '新增' || props.operate === '编辑' ) ? false : (props.disabled || false);
  if (props.dataTableId) {
    await initByTableId(props.dataTableId);
  } else if (props.formFieldList.length > 0) {
    await initByFormField(props.formFieldList);
  }
  await nextTick(() => initializing.value = false);
};

const initAutofillValue = async() => {
  for (const data of (getData() || [])) {
    await autofillValue(data);
  }
};

const autofillValue = async(data, triggerFieldName) => {
  if (!props.autofillList || props.autofillList.length === 0) return;
  for (const autofill of props.autofillList) {
    if (!autofill.triggerFieldValue) {
      autofill.triggerFieldValue = {};
    }

    if (!autofill.fieldList
      || autofill.fieldList.length === 0
      || !autofill.triggerFieldName
      || (triggerFieldName && autofill.triggerFieldName !== triggerFieldName)) continue;

    const id = data.newRowFlag || data.id || tool.uuid();
    if (data[autofill.triggerFieldName]
        && data[autofill.triggerFieldName] !== autofill.triggerFieldValue[id]) {
      let url = '/codeless/data-model/' + autofill.dataModelId + '/data';
      let params = {};
      params[autofill.compareFieldName] = data[autofill.triggerFieldName];

      const res = await api.post(url, params);
      if (!res.data) continue;

      for (const field of autofill.fieldList) {
        data[field.autofillFieldName] = res.data[field.sourceFieldName] || null;
        if (res.data[field.sourceFieldName + "_name"]) {
          data[field.autofillFieldName + "_name"] = res.data[field.sourceFieldName + "_name"];
        }
      }
    }
    autofill.triggerFieldValue[id] = data[autofill.triggerFieldName];
  }
};

watch(() => props.dataList, () => {
  initTableData();
  initAutofillValue();
});

watch(() => tool.deepClone(formData.value.list), (newList, oldList) => {
  if (disabled.value) return;
  if (!newList || newList.length === 0 || newList.length !== oldList.length) return;
  for (let i=0;i<newList.length;i++) {
    changeWatchValue(newList[i], oldList[i]);
  }
}, {deep: true});

const changeWatchValue = (newVal, oldValue) => {
  for (const prop in newVal) {
    if ((newVal[prop] || '') !== (oldValue[prop] || '')) {
      if (props.customFun && props.customFun['change_' + prop]) {
        updateValue(props.customFun['change_' + prop](tool.deepClone(newVal), context), newVal);
      }
    }
  }

  if (props.customFun && props.customFun.change) {
    updateValue(props.customFun.change(tool.deepClone(newVal), context), newVal);
  }
};

const updateValue = (result, data) => {
  if (result instanceof Error) {
    ElMessage.error(result.message);
  } else if (result instanceof Promise) {
    result.then(res => {
      for (const p in res.data || {}) {
        for (let i=0; i<formData.value.list.length; i++) {
          const row = formData.value.list[i];
          if (row['id'] && row['id'] === data['id']) {
            row[p] = res.data[p];
          } else if (row['newRowFlag'] && row['newRowFlag'] === data['newRowFlag']) {
            row[p] = res.data[p];
          }
        }
      }
    });
  } else {
    for (const p in result || {}) {
      for (let i=0; i<formData.value.list.length; i++) {
        const row = formData.value.list[i];
        if (row['id'] && row['id'] === data['id']) {
          row[p] = result[p];
        } else if (row['newRowFlag'] && row['newRowFlag'] === data['newRowFlag']) {
          row[p] = result[p];
        }
      }
    }
  }
};

const context = {
  getUser: function() {
    return userStore.getUserData();
  },

  getOrg: function() {
    return userStore.getOrgData();
  },

  getPageParam: function () {
    return page?.getPageParam();
  },

  getPageData: function() {
    return page?.getPageData();
  },

  runScript: function(id, params) {
    return api.runScript(id, params);
  }
};

onMounted(() => {
  init();
  initAutofillValue();
});

defineExpose({ validate, getData });
</script>

<style scoped>
.cc-edit-table .cc-table :deep(.el-form-item__content) {
  justify-content: center;
}
</style>